﻿using System;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using Csla;
using Csla.Rules;
using Csla.Rules.CommonRules;
using Csla.Server;
using BizControl.DalLinq;
using Csla.Data;
using Csla.Reflection;
using System.Data.Linq;
using System.Text.RegularExpressions;
using BizControl.Library.BusinessObjects.People;
using BizControl.Resources;

namespace BizControl.Library.BusinessObjects.Notes
{
  [Serializable()]
  public class NoteBO : BusinessBase<NoteBO>, ISupportEmptyValue
  {
    #region Business Methods

    private static readonly PropertyInfo<Guid> NoteIdProperty = RegisterProperty<Guid>(c => c.NoteId);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"NoteNoteIdPropertyRequiredError")]
    public Guid NoteId
    {
      get { return GetProperty(NoteIdProperty); }
      private set { SetProperty(NoteIdProperty, value); }
    }

    private static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"NoteNamePropertyRequiredError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"NoteNameProperty")]
    public string Name
    {
      get { return GetProperty(NameProperty); }
      set { SetProperty(NameProperty, value); }
    }

    private static readonly PropertyInfo<string> ContentProperty = RegisterProperty<string>(c => c.Content);
    [Display(ResourceType = typeof(PropertiesNames), Name = @"NoteContentProperty")]
    public string Content
    {
      get { return GetProperty(ContentProperty); }
      set { SetProperty(ContentProperty, value); }
    }

    private static readonly PropertyInfo<ObjectPriority> PriorityProperty = RegisterProperty<ObjectPriority>(c => c.Priority, null, ObjectPriority.Normal);
    [Display(ResourceType = typeof(PropertiesNames), Name = @"NotePriorityProperty")]
    public int Priority
    {
      get { return GetPropertyConvert<ObjectPriority, int>(PriorityProperty); }
      set { SetPropertyConvert<ObjectPriority, int>(PriorityProperty, value); }
    }

    #region Common properties

    private static readonly PropertyInfo<bool> IsDeletedFieldProperty = RegisterProperty<bool>(c => c.IsDeletedField, null, false);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"IsDeletedRequiredError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"IsDeletedFieldProperty")]
    public bool IsDeletedField
    {
      get { return GetProperty(IsDeletedFieldProperty); }
      private set { SetProperty(IsDeletedFieldProperty, value); }
    }

    private static readonly PropertyInfo<Guid?> CreatedByProperty = RegisterProperty<Guid?>(c => c.CreatedById);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CreatedByRequiredPropertyError")]
    public Guid? CreatedById
    {
      get { return GetProperty(CreatedByProperty); }
      private set { SetProperty(CreatedByProperty, value); }
    }

    private static readonly PropertyInfo<DateTime> CreatedOnProperty = RegisterProperty<DateTime>(c => c.CreatedOn);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CreatedOnRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CreatedOnProperty")]
    public DateTime CreatedOn
    {
      get { return GetProperty(CreatedOnProperty); }
      private set { SetProperty(CreatedOnProperty, value); }
    }

    private static readonly PropertyInfo<DateTime> LastChangedProperty = RegisterProperty<DateTime>(c => c.LastChanged);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"LastChangedRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"LastChangedProperty")]
    public DateTime LastChanged
    {
      get { return GetProperty(LastChangedProperty); }
      private set { SetProperty(LastChangedProperty, value); }
    }

    #endregion

    internal void LoadData(Note noteDB)
    {
      if (noteDB == null) return;
      NoteId = noteDB.NoteId;
      Name = noteDB.Name;
      Content = noteDB.Content;
      Priority = noteDB.Priority ?? (int)ObjectPriority.Normal;

      // Common properties
      CreatedById = noteDB.CreatedBy;
      CreatedOn = noteDB.CreatedOn;
      LastChanged = noteDB.LastChanged;
      IsDeletedField = noteDB.IsDeleted;
    }

    #endregion

    #region Business Rules

    protected override void AddBusinessRules()
    {
      base.AddBusinessRules();
    }

    #endregion

    #region  Data Access

    private void Child_Create(PersonBO person)
    {
      if (person == null) throw new ArgumentNullException(ExceptionsMessages.PersonNullReference);
      using (BypassPropertyChecks)
      {
        NoteId = Guid.NewGuid();
        CreatedById = person.PersonId;
        CreatedOn = DateTime.Now;
      }
      base.Child_Create();
    }

    private void Child_Fetch(Note data)
    {
      using (BypassPropertyChecks)
      {
        LoadData(data);
      }
    }

    private void Child_Insert()
    {
      using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
      {
        using (BypassPropertyChecks)
        {
          ctx.DataContext.AddNote(
            NoteId,
            Name,
            Content,
            Priority,
            CreatedById == null || IsEmpty() ? (Guid?)null : CreatedById,
            IsDeletedField,
            CreatedOn,
            LastChanged);
        }
      }
    }

    private void Child_Update()
    {
      using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
      {
        if (IsSelfDirty)
        {
          LastChanged = DateTime.Now;
          using (BypassPropertyChecks)
          {
            ctx.DataContext.UpdateNote(
              NoteId,
              Name,
              Content,
              Priority,
              IsDeletedField,
              LastChanged);
          }
        }
      }
    }

    private void Child_DeleteSelf()
    {
      using (BypassPropertyChecks)
      {
        IsDeletedField = true;
        Child_Update();
      }
    }

    #endregion

    #region  Factory Methods

    internal static NoteBO NewNote(PersonBO person)
    {
      return Csla.DataPortal.CreateChild<NoteBO>(person);
    }

    internal static NoteBO GetNote(Note data)
    {
      return Csla.DataPortal.FetchChild<NoteBO>(data);
    }

    private NoteBO()
    { /* require use of factory methods */ }

    #endregion

    #region ISupportEmtpyValue Members

    public bool IsEmpty()
    {
      return NoteId == Guid.Empty;
    }

    #endregion
  }
}
